/**
 * 事件基类，提供DOM事件和自定义事件侦听、触发、销毁功能，自定义事件基于Vue实现，面向对象类可继承该类实现事件相关功能
 * @module utils/events
 */

import { on, off } from 'dom';
import bus from '@/utils/bus';

/**
 * 事件处理基类
 * @export
 */
export default class Events {
	/**
	 * @constructor
	 */
	constructor() {
		/**
		 * DOM事件句柄对象handler缓存集合,  私有属性
		 * @type {Object[]}
		 * @property {Object[]} handler
		 * @property  {HtmlElement} handler.el DOM元素
		 * @property {String} handler.eventName 事件名称，如: click、mouseenter、keydown
		 * @property {Function} handler.callback 事件回调函数
		 * @property {Function} handler.proxy 事件回调函数代理，更换了作用域this指向当前实例
		 */
		this.__handlers__ = [];

		/**
		 * 自定义事件处理对象，私有属性
		 * @type {Vue}
		 */
		this.__event__ = bus;
	}

	/**
	 * 绑定DOM事件
	 * @param {HtmlElement} el 元素DOM对象
	 * @param {String} eventName 事件名称如：click、mouseenter、keydown
	 * @param {Function} callback 事件回调函数
	 */
	on(el, eventName, callback) {
		const proxy = callback.bind(this);
		const handler = { el, eventName, callback, proxy };
		this.__handlers__.push(handler);
		on(el, eventName, proxy);
	}

	/**
	 * 绑定自定义事件 $on(name, handler)
	 * @param {String} name 事件名称
	 * @param {Function} handler 事件处理函数
	 * @returns {Vue}
	 */
	$on() {
		return this.__event__.on.apply(this.__event__, arguments);
	}

	/**
	 * 销毁指定DOM事件
	 * @param {HtmlElement} el DOM元素
	 * @param {String} [eventName] 事件名称如：click、mouseenter、keydown，可选参数，如不传，即表示销毁当前元素的全部事件
	 * @param {Function} [callback] 事件回调函数，可选，如不传，即表示销毁当前元素指定类型的事件
	 */
	off(el, eventName, callback) {
		if (!el) return;
		const length = arguments.length;
		this.__handlers__.forEach((item, index) => {
			switch (length) {
				case 3:
					if (item.el === el && item.eventName === eventName && item.callback === callback) {
						off(item.el, item.eventName, item.proxy);
						this.__handlers__.splice(index, 1);
					}
					break;
				case 2:
					if (item.el === el && item.eventName === eventName) {
						off(item.el, item.eventName, item.proxy);
						this.__handlers__.splice(index, 1);
					}
					break;
				case 1:
					if (item.el === el) {
						off(item.el, item.eventName, item.proxy);
						this.__handlers__.splice(index, 1);
					}
					break;
			}
		});
	}

	/**
	 * 销毁自定义事件$off(name, handler)
	 * @param {String} [name] 事件名称，可选，不传表示销毁当前实例的全部事件
	 * @param {Function} [handler] 事件回调函数，可选，不传表示销毁当前实例指定时间名称的全部事件
	 * @returns {Vue}
	 */
	$off() {
		return this.__event__.off.apply(this.__event__, arguments);
	}

	/**
	 * 触发自定义事件	$emit(name, handler)
	 * @param {string} name 事件名称
	 * @param {Function} handler 事件回调函数
	 * @returns {Vue}
	 */
	$emit() {
		return this.__event__.emit.apply(this.__event__, arguments);
	}

	/**
	 * 销毁实例，把DOM和自定义事件全部销毁，释放内存
	 */
	destroy() {
		this.__handlers__.forEach((item) => {
			off(item.el, item.eventName, item.proxy);
		});
		this.__handlers__ = [];
		this.__event__.$off();
		this.__event__.$destroy();
	}
}
